docs(metadata-protocol): the getMetaItems gate enumerates six rest-server.ts call sites, not five, and names the transitive diagnostics door - #16117
Conversation
…rver call sites, not five, and names the transitive diagnostics door The `[#14683]` gate docblock above `getMetaItems`' `organizationIdForMetaRead` call called the `GET /meta/:type` list door "the only door that both gates and reaches this method", then accounted for "the four remaining" `organizationIdForMetaRead` call sites in `rest-server.ts`. One named plus four remaining is five; that file has SIX, and the missing one is `GET /meta/diagnostics?type=`, which both gates and reaches this method. It was missed because it does not call `getMetaItems`. It calls `getMetaDiagnostics`, whose `?type=` arm sets `targetTypes = [request.type]` and loops `getMetaItems({ type: t, organizationId, ... })` over it, so a grep for doors invoking `getMetaItems` cannot see it. That hop is also undeclared: `getMetaDiagnostics` is not a member of `MetadataProtocol`, neither required nor optional, so the door reaches it through a runtime cast behind a 501 feature-detect - real at runtime, invisible to the type system. The enumeration is what #14683 offers as evidence that its change is a no-op for every already-gating caller. That conclusion is measured and holds; only the enumeration backing it was short a caller. Comment only: no behaviour change, no schema change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
📓 Docs Drift CheckThis PR changes 1 package(s): 31 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 9 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ca9565b5c96481a63a7543ca2320f6c5055775a8 && git checkout ca9565b5c96481a63a7543ca2320f6c5055775a8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a4816a79d0396d0fd10696cdf95d66e55aef92d3 ebdb9d6ae7d7e853d2df0dccdf4f684fe928d72d && git checkout -B drift-repro a4816a79d0396d0fd10696cdf95d66e55aef92d3 && git merge --no-ff ebdb9d6ae7d7e853d2df0dccdf4f684fe928d72d
node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3
|
Fixes #15621
The
[#14683]gate docblock abovegetMetaItems'organizationIdForMetaReadcallcalled the
GET /meta/:typelist door "the only door that both gates and reachesthis method", and then accounted for "the four remaining"
organizationIdForMetaReadcall sites in
rest-server.ts. One named plus four remaining is five. That file hassix, and the missing one —
GET /meta/diagnostics?type=— both gates and reachesthis method.
Comment only: no behaviour change, no schema change, no exported symbol touched.
Where the text actually is
The card measured the block at
:6928-6942and triage at:6926-6942; #15592 haslanded since. Re-located by text, not by line number, on
origin/mainat9b459b791: the enumeration is atpackages/metadata-protocol/src/protocol.ts:6800-6816,inside
getMetaItems(declared:6750), immediately aboveconst orgId = organizationIdForMetaRead(request.type, request.organizationId);.The census, re-counted here, with its dimension stated
git grep -c organizationIdForMetaRead -- packages/rest/src/rest-server.tsanswers15 on this tree — that is lines, not call sites. (Triage read 13; the total has
moved by two comment mentions since. The call-site count did not move.) Classified
line by line:
:58:3499,:4943,:5007,:5030,:5803,:7073,:7088,:7637:3504,:5066,:5338,:6239,:7095,:76631 + 8 + 6 = 15. The six call sites and what each reaches:
:3504/meta/:type/:name/layers(viaserveMetaItemLayered)getMetaItemLayered:3521:5066/meta/diagnostics?type=getMetaItems, transitively:5338GET /meta/:typelist doorgetMetaItems:5354:6239getMetaItemCached:6290/getMetaItem:6413:7095/historyhistoryMetaItem:7146:7663/diffdiffMetaItem:7668Positive control for the census: the same classification pass over the same file
yields a non-zero count in every one of its three buckets, and the six call-site rows
were each confirmed by reading the destination call rather than by pattern alone.
Why the miss happened, and how the list is now built
The diagnostics door does not call
getMetaItems. It callsgetMetaDiagnostics,whose
?type=arm setstargetTypes = [request.type]and loopsgetMetaItems({ type: t, organizationId, ... })per swept type (protocol.ts:6167-6174).A grep for doors invoking
getMetaItemstherefore cannot see it.So the list is now derived from the callee side and stated as closed.
this.getMetaItems(has exactly three callers in this file —getMetaDiagnostics(
:6170),searchAll(:11393) andfindReferencesToMeta(:21450) — and atransitive-closure walk of the class's call graph confirms no other method reaches it
at any depth. In particular none of
getMetaItemLayered/getMetaItem/getMetaItemCached/historyMetaItem/diffMetaItemreaches it, which is whatlicenses the surviving "never this method" clause.
Positive control for the closure instrument: run on the same graph, it reports
throwMetadataServiceUnavailableas reached at depth 2 and 3 (bysaveMetaItem,getMetaItemCached,duplicatePackage,migrateStoredMetadata), so the zero resultabove is a measurement and not a broken traversal.
findReferencesToMetais the third caller and gates nothing, deliberately — its doorspends the organization on the reference SOURCES while
req.params.typeis the TARGET(
rest-server.ts:5803-5816), so it hands the tenant over raw and is not one of the"already gates" callers this paragraph is about. That is now written down too, so the
next reader does not re-derive it as an omission.
The undeclared hop
getMetaDiagnosticsis not a member ofMetadataProtocol— neither required noroptional. Verified on this tree by a brace-balanced scan of the interface
(
packages/spec/src/api/protocol.zod.ts:3381-3459):getMetaItems,getMetaItem,getMetaItemLayeredandhistoryMetaItemare declared there;getMetaDiagnosticsisabsent. The door reaches it through a
(p as any)cast behind a 501 feature-detect(
rest-server.ts:4922-4927). Real at runtime, invisible to the type system — which isexactly the kind of path a caller census has to be told rather than left to derive.
Scope
#14683's conclusion is not reopened. It is measured and holds — PR #15619 pinned it
30/30. Only the enumeration backing it was short a caller.
The
packages/resthalf is tracked separately as #15620 and is not addressed here;#15620 remains open.
Verification
dispatch-gates.mjs --repo objectstack-ai/objectstackderived 40 runnablefamilies for this diff (32 by path + 1 by change kind + 7 declared whole-tree).
38 ran and exited 0. Verdict lines quoted rather than bare exit codes, e.g.
check-nul-bytes: OK (scanned 7804 text file(s) ... no raw ASCII control bytes)and
doc authoring guard: ... clean.pnpm check:dts-closure— green:76/76 declared declaration file(s) present across 14 package(s).pnpm check:dual-build-cjs-loads— NOT MEASURED, not red. It exits 3 withRun pnpm build first. This is NOT a pass: nothing was measured.(49 packages haveno
distin this worktree). It needs a repo-wide build; CI's Build Core covers it.ebdb9d6ae:pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2 src/get-meta-items-org-read-gate.test.ts src/protocol.diagnostics-store-outage.test.ts— 2 files, 204 tests, 204 passed.Published-surface measurement (Clause-②)
Clause-②: no— measured, not assumed. Full ablation against the published artefacts:built at head, swapped this file back to
origin/main's copy, rebuilt, compared everyartefact
files: ["dist"]ships.original text 1 hit; blob
89436302vs HEAD blob87087b71).index.d.ts,index.d.cts,index.js,index.cjs— all four byte-IDENTICALacross the ablation.
index.js.mapandindex.cjs.mapdiffer, because a sourcemap embedssourcesContentverbatim. Control: pre-existing text from this same docblock thatthis PR never touched (
THE HARM IS RESURRECTION,Gate AFTER the fold) is presentin exactly those two files and absent from the other four — so this is the comment
family's normal behaviour, not something this diff introduced.
87087b71,git diff HEADempty,git status --porcelainempty (index included), and the restore leg rebuilt sodistmatches head.No declaration moves, no accept/reject behaviour moves, no exported symbol changes.
Changeset
None, and
skip-changesetapplied: this publishes nothing from any package. Precedenton this exact shape is
b339a38377—docs(metadata-protocol): record that hidden does not govern getUiView's default sort, one file, comment-only, no changeset. Theablation above is the measurement behind the claim.
Generated by Claude Code